package com.tuzhi.util;


import org.apache.commons.lang3.math.NumberUtils;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class NumberTzUtil extends NumberUtils {

    public static BigDecimal divide(BigDecimal bigDecimal1, BigDecimal bigDecimal2) {
        return bigDecimal1.divide(bigDecimal2, 2, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 判断是否有小数位
     * @param bigDecimal
     * @return
     */
    public static boolean hasDecimal(BigDecimal bigDecimal) {
        return hasDecimal(bigDecimal, 2, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 判断是否有小数位
     * @param bigDecimal
     * @param scale 保留小数位
     * @param round 进位模式
     * @return
     */
    public static boolean hasDecimal(BigDecimal bigDecimal, int scale, int round) {
        if (bigDecimal != null) {
            BigDecimal tmp = bigDecimal.setScale(scale, round);
            if (new BigDecimal(tmp.intValue()).compareTo(tmp) == 0){
                //整数
                return false;
            } else {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断是否有小数位
     * @param bigDecimal
     * @param scale 保留小数位
     * @return
     */
    public static boolean hasDecimal(BigDecimal bigDecimal, int scale) {
        return hasDecimal(bigDecimal, scale, BigDecimal.ROUND_HALF_UP);
    }



    /**
     * 指定误差范围内相等
     * @param b1
     * @param b2
     * @param d     误差值
     * @return
     */
    public static boolean equals4BigDecimal(BigDecimal b1, BigDecimal b2, double d) {
        if (b1 == null && b2 == null) {
            return true;
        }
        if (b1 != null && b2 != null) {
            return b1.subtract(b2).abs().doubleValue() <= d;
        }
        return false;
    }

    /**
     * 指定误差范围内相等
     * @param b1
     * @param b2
     * @param d     误差值
     * @return
     */
    public static boolean equals4Double(Double b1, Double b2, double d) {
        if (b1 == null && b2 == null) {
            return true;
        }
        if (b1 != null && b2 != null) {
            return ((b1 > b2)? b1 - b2: b2 - b1) <= d;
        }
        return false;
    }

    /**
     * 指定误差范围内相等
     * @param b1
     * @param b2
     * @param d     误差值
     * @return
     */
    public static boolean equals4Float(Float b1, Float b2, float d) {
        if (b1 == null && b2 == null) {
            return true;
        }
        if (b1 != null && b2 != null) {
            return ((b1 > b2)? b1 - b2: b2 - b1) <= d;
        }
        return false;
    }

    public static boolean floatEquals(float a, float b, float epsilon) {
        Double doubleA = new BigDecimal(Float.toString(a)).doubleValue();
        Double doubleB = new BigDecimal(Float.toString(b)).doubleValue();
        return Math.abs(doubleA - doubleB) <= epsilon;
    }

    public static int doubleCompare(Double a, Double b, Double epsilon) {
        if (equals4Double(a, b, epsilon)) return 0;
        return a.compareTo(b);
    }

    public static int floatCompare(Float a, Float b, float epsilon) {
        if (floatEquals(a, b, epsilon)) return 0;
        return a.compareTo(b);
    }

    public static float max(Float[] values) {
        List<Float> list = Arrays.asList(values);
        return Collections.max(list);
    }

    public static void main(String[] args) {

        BigDecimal bd = new BigDecimal("12.00215458");
        System.out.println(bd.setScale(4, BigDecimal.ROUND_HALF_UP));
        System.out.println(bd.setScale(2, BigDecimal.ROUND_HALF_UP));
        System.out.println(bd.toString());

        System.out.println(hasDecimal(bd));
        System.out.println(hasDecimal(bd, 2));
        System.out.println(hasDecimal(bd, 3));

        String s1 = "05123.21";
        System.out.println(String.format("s=%s, %s", s1, isCreatable(s1)));
        String s2 = "-05123.21";
        System.out.println(String.format("s=%s, %s", s2, isCreatable(s2)));
        String s3 = "-00.512321";
        System.out.println(String.format("s=%s, %s", s3, isCreatable(s3)));

        String s4 = "-00512321";
        System.out.println(String.format("s=%s, %s", s4, isDigits(s4)));
        String s5 = "00512321";
        System.out.println(String.format("s=%s, %s", s5, isDigits(s5)));
        String s6 = "0.512321";
        System.out.println(String.format("s=%s, %s", s6, isDigits(s6)));


        /**
         * @方法： public static int toInt(String str)
         * @作用： 将一个字符串转换成int类型
         * @参数： str-将要转换的字符串，可能会是null
         * @返回值： 转换失败返回0，否则返回转换的结果值
         */
        System.out.println(toInt("5")); //返回5
        System.out.println(toInt("")); //返回0
        System.out.println(toInt(null)); //返回0

        /**
         * @方法： public static int toInt(String str, int defaultValue)
         * @作用： 将一个字符串转换成int类型，如果转换失败就返回一个默认值defaultValue
         * @参数： str-将要转换的字符串，可能会是null;
         *        defaultValue-默认值，如果转换失败就显示默认值
         * @返回值： 如果转换失败就返回一个默认值defaultValue，否则返回转换的结果值
         */
        System.out.println(toInt(null, 0)); // 返回 0
        System.out.println(toInt("", 0)); // 返回 0
        System.out.println(toInt("5", 0)); // 返回 5

        /**
         * @方法： public static long toLong(String str)
         * @作用： 将一个字符串数据转换成一个long类型数据，如果转换失败返回0
         * @参数： 转换的字符串，可能为null;
         * @返回值： 字符串代表的long数据类型，或者转换失败的默认值0
         */
        System.out.println(toLong(null)); // 返回 0
        System.out.println(toLong("6")); // 返回 6
        System.out.println(toLong("")); // 返回 0

        /**
         * @方法： public static long toLong(String str, long defaultValue)
         * @作用： 将一个字符串数据转换成一个long类型数据，如果转换失败返回默认值
         * @参数： str-转换的字符串，可能为null;
         *        defaultValue-默认值
         * @返回值： 字符串代表的long数据类型，转换失败的时候返回默认值
         */
        System.out.println(toLong(null, 0)); // 返回 0
        System.out.println(toLong("6", 0)); // 返回 6
        System.out.println(toLong("", 0)); // 返回 0

        //double（双精度浮点数）和float（单精度浮点数）:
        //在内存中占的字节数不同，单精度浮点数占4个字节，双精度浮点数占8个字节；
        //有效位数不同，单精度浮点数有效位数是8位，双精度浮点数有效位数是16位；
        //位数不同，单精度浮点的表示范围：-3.40E+38 ~ +3.40E+38，双精度浮点的表示范围：-1.79E+308 ~ +1.79E+308
        //处理速度不同，一般来说处理器处理单精度浮点数的速度比处理双精度的浮点数速度要快；

        /**
         * @方法： public static double toDouble(String str)
         * @作用： 将一个字符串转换成double类型
         * @参数： str-转换的字符串，可能为null
         * @返回值： 字符串代表的double值；如果转换失败返回0.0d，如果字符串是null返回0.0d
         */
        System.out.println(toDouble((String) null)); // 返回 0.0
        System.out.println(toDouble("")); // 返回 0.0
        System.out.println(toDouble("12")); // 返回 12.0

        /**
         * @方法： public static double toDouble(String str, double defaultValue)
         *
         * @作用： 将一个字符串转换成double类型，如果转换失败将会把默认值defaultValue返回
         * @参数： str-转换的字符串，可能为null;
         *        defaultValue-默认值
         * @返回值： 转换成功返回字符串代表的double数据类型；如果转换失败返回0.0d;如果字符串值是null将会把默认值返回
         */
        System.out.println(toDouble((String) null, 0.001d)); // 返回 0.001
        System.out.println(toDouble("", 0.001d)); // 返回 0.001
        System.out.println(toDouble("12", 0.001d)); // 返回 12.0

        /**
         * @方法： public static float toFloat(String str)
         * @作用： 将一个字符串转换成float数据类型，如果转型失败返回0.0f;如果传入参数字符串为null，返回默认值0
         * @参数： str-转换的字符串，可能为null
         * @返回值： 转换成功返回字符串代表的float数据类型，如果转型失败返回0
         */
        System.out.println(toFloat(null)); // 返回 0
        System.out.println(toFloat("")); // 返回 0
        System.out.println(toFloat("1.6")); // 返回 1.6

        /**
         * @方法： public static float toFloat(String str, float defaultValue)
         * @作用： 将一个字符串转换成float数据类型
         * @参数： str-转换的字符串，可能为null
         *        defaultValue-默认值
         * @返回值： 转换成功返回字符串代表的float数据类型，否则返回默认值defaultValue
         *          (如果转型失败返回默认值defaultValue;如果传入参数字符串为null，返回默认值defaultValue)
         */
        System.out.println(toFloat(null, 0.0001f)); // 返回 1.0E-4(1.0 * 10^﹣4)
        System.out.println(toFloat("",0.001f)); // 返回 0.001
        System.out.println(toFloat("1.6",0.0001f)); // 返回 1.6


        /**
         * @方法： public static boolean isDigits(String str)
         * @作用： 检查字符串是否是只包含数字字符，null和空将会返回false
         * @参数： str-检查的字符串 str可为null
         * @返回值： 只包含数字返回true，否则返回false
         */
        System.out.println(isDigits("6666! Life is so short,do something to make yourself happy,such as coding! 6666")); // 返回 false
        System.out.println(isDigits("6666！生活如此短暂，做一些使自己开心的事，比如编程！6666"));  // 返回 false
        System.out.println(isDigits("666666"));  // 返回 true

        /**
         * @方法： public static boolean isParsable(String str)
         * @作用： 检验提供的字符串是否可以转换为number,
         *        可解析的number包括下面的方法 Integer.parseInt(String), Long.parseLong(String),
         *        Float.parseFloat(String) or Double.parseDouble(String)，
         *        当调用上面的方法时这个方法可以替代ParseException异常；十六进制和科学符号被认为是不可解析的；null和空字符串返回false；
         * @参数： str-检验的字符串 str可为null
         * @返回值： true-如果参数是可转换的字符串，否则返回false
         */
        System.out.println(isParsable(""));  // 返回 false
        System.out.println(isParsable(null));  // 返回 false
        System.out.println(isParsable("12"));  // 返回 true
        System.out.println(isParsable("12.0")); // 返回 true
        System.out.println(isParsable("12.3")); // 返回 true
        System.out.println(isParsable("7a"));  // 返回 false (十六进制7a对应十进制122)
        System.out.println(isParsable("1.0E-4")); // 返回 false


        /**
         * @方法： public static boolean isCreatable(String str)
         * @作用： 检查字符串是否是一个有效的number；
         *        有效数字包括进制标有0x或0X预选项，八进制数、科学记数法和标有类型限定符的数字，
         *        以 前导零开头的非十六进制字符串被视为八进制值，因此字符串09将返回false,因为9不是有效的八进制，
         *        然而从0开始的数字，被视为十进制；null、空或者空串将返回false;
         * @参数： str-检查的字符串； str可为null
         * @返回值： true-如果字符串是一个正确格式化的数字，否则返回false
         */
        System.out.println(isCreatable(null)); // 返回 false
        System.out.println(isCreatable(" ")); // 返回 false
        System.out.println(isCreatable("")); // 返回 false
        System.out.println(isCreatable("09")); // 返回 false
        System.out.println(isCreatable("9")); // 返回 true
        System.out.println(isCreatable("0x56")); // 返回 true
        System.out.println(isCreatable("0X20")); // 返回 true

        /**
         * @方法： public static int compare(int x, int y)
         * @作用： 比较两个int数值
         * @参数： x-第一个int比较值，y-第二个int比较值
         * @返回值： 如果 x==y 返回0；x<y 返回负数(-1)；x>y 返回正数(1)
         */
        System.out.println(compare(1,1)); // 返回 0
        System.out.println(compare(1,2)); // 返回 -1
        System.out.println(compare(3,2)); // 返回 1

        /**
         * @方法： public static int compare(long x, long y)
         * @作用： 比较两个int数值
         * @参数： x-第一个long比较值，y-第二个long比较值
         * @返回值： 如果 x==y 返回0；x<y 返回负数(-1)；x>y 返回正数(1)
         */
        System.out.println(compare(1L,1L)); // 返回 0
        System.out.println(compare(3L,2L)); // 返回 1
        System.out.println(compare(5L,6L)); // 返回 -1

        /**
         * @方法： public static BigDecimal createBigDecimal(String str)
         * @作用： 将一个字符串转换成BigDecimal类型，如果字符串是null将会返回null
         * @参数： str-转换的字符串，可能为null
         * @返回值： 被转换的BigDecimal;如果输入的字符串是null将会返回null
         * @抛出异常： 空串或不能解析将会抛出 NumberFormatException
         */
//        System.out.println(createBigDecimal("abc")); // 报异常 java.lang.NumberFormatException
//        System.out.println(createBigDecimal("")); // 报异常 java.lang.NumberFormatException: A blank string is not a valid number
        System.out.println(createBigDecimal(null)); // 返回 null
        System.out.println(createBigDecimal("1235")); // 返回 1235

        /**
         * @方法： public static Double createDouble(String str)
         * @作用： 将一个字符串转换成Double类型，如果输入字符串是null将会返回null
         * @参数： str-转换的字符串，可能为null;
         * @返回值： 被转换的Double值（如果输入字符串是null将会返回null）；
         * @抛出异常： 如果值不能解析将会抛出NumberFormatException ;
         */
        System.out.println(createDouble(null)); // 返回 null
//        System.out.println(createDouble("asc")); // 返回 java.lang.NumberFormatException: For input string: "asc"
        System.out.println(createDouble("12")); // 返回 12.0

        /**
         * @方法： public static Long createLong(String str)
         * @作用： 将一个字符串转换为Long数据类型，注：前导零表示八进制；空间不剪裁。如果字符串值是null将会返回null；
         * @参数： str-转换的字符串，可能为null；
         * @返回值： 被转换的Long数据（如果输入的是null将返回null）；
         * @抛出异常： 如果值不能被转换将会抛出NumberFormatException异常；
         */
//        System.out.println(createLong("")); // java.lang.NumberFormatException: Zero length string
        System.out.println(createLong(null));  // 返回 null
        System.out.println(createLong("123")); // 返回 123

        /**
         * @方法： public static BigInteger createBigInteger(String str)
         * @作用： 将一个字符串转换为BigDecimal类型，自3.2以来，它处理六（0x或#）和八进制（0）符号。如果字符串为null将会返回null
         * @参数： str-转换的字符串,可能为null
         * @返回参数： 被转换的BigDecimal[如果输入字符串为null将返回null]
         * @抛出异常： 如果值不能被转换将会抛出NumberFormatException异常
         */
//        System.out.println(createBigInteger("")); // java.lang.NumberFormatException: Zero length BigInteger
        System.out.println(createBigInteger(null)); // 返回 null
//        System.out.println(createBigInteger("12s"));// java.lang.NumberFormatException: For input string: "12s"
        System.out.println(createBigInteger("12")); // 返回 12

        /**
         * @方法： public static Number createNumber(String str)
         * @作用： 将一个字符串值转换为java.lang.Number类型
         * @参数： str-转换字符串,可能为null
         * @返回值： 从字符串创建的Number值;如果输入的字符串为null则返回null
         * @抛出异常： 如果值不能被转换将会抛出NumberFormatException异常
         */
        System.out.println(createNumber("123")); // 返回 123
//        System.out.println(createNumber("12s")); // 返回 java.lang.NumberFormatException: 12s is not a valid number
        System.out.println(createNumber("123.0")); // 返回 123.0
//        System.out.println(createNumber("")); // 返回 java.lang.NumberFormatException: A blank string is not a valid number
        System.out.println(createNumber(null)); // 返回 null

        /**
         * @方法： public static int max(int a, int b, int c)
         * @作用： 获取三个int值中最大的一个
         * @参数： a-值1，b-值2，c-值3
         * @返回值： 最大的值
         * @抛出异常： 如果参数是空抛出java.lang.IllegalArgumentException: Array cannot be empty
         */
        System.out.println(max(1,5,2,9,10)); // 返回 10
//        System.out.println(max()); // 返回 java.lang.IllegalArgumentException: Array cannot be empty

        /**
         * @方法： public static int max(int… array)
         * @作用： 返回数组中最大的值
         * @参数： array-一定不能为空或者null
         * @返回值： 数组中最大的值
         * @抛出异常： 如果数组为空或者null将会抛出IllegalArgumentException异常
         */
        System.out.println(max(1,2,3,4,5,9,1.0,2.0,2.5,9.8)); //  返回 9.8

        //余数
        BigDecimal big = new BigDecimal("21.20");
        BigDecimal big2 = new BigDecimal("4.0");
        System.out.println(big.remainder(big2));

    }

}
